/*
 * PruebaArchivoFrontCoding.cpp
 *
 *  Created on: 02/06/2013
 *      Author: jonathan
 */

#include "PruebaArchivoFrontCoding.h"
#include "../indexado/archivos/ArchivoFrontCoding.h"
#include "../general/estructuras/Termino.h"
#include "../commons/bitstream.h"
#include "../indexado/estructuras/EntradaIndice.h"
#include "../commons/ArchivoUtils.h"
#include "../commons/InfoRepositorioActual.h"
void PruebaArchivoFrontCoding::after() {

}

void PruebaArchivoFrontCoding::verificarString(string cadena , BitStream& stream, ResultadoTest& res){
	  char c;
	  for (string::iterator it=cadena.begin(); it!=cadena.end(); ++it){
		  stream.get(c);
		res.assertTrue(c == *it, "Error leyendo la cadena: "+ cadena);
	  }


}

ResultadoTest PruebaArchivoFrontCoding::escribirConCoincidencias() {
	ResultadoTest res("escribirConCoincidencias");
	ArchivoFrontCoding arch("archivoFC", "archivoPtrosFC", 2, ios_base::out);
	Termino * t1 = this->crearTermino("barco", 2, this->crearDocumento(1, 2, 1, 2), this->crearDocumento(3, 2, 3, 5));
	Termino * t2 = this->crearTermino("barcasa", 1, this->crearDocumento(3, 2, 3, 5));

	EntradaIndice * ent1 = arch.escribir(*t1);
	EntradaIndice * ent2 = arch.escribir(*t2);
	arch.close();
	res.assertTrue(ent1->getCharsDistintos() == 5, "Calculo mal el primer termino (charsdistintos)");
	res.assertTrue(ent2->getCharsDistintos() == 3, "Calculo mal el segundo termino (charsdistintos)");
	res.assertTrue(ent1->getPrincipal(), "El primero no fue marcado como ppal");
	res.assertTrue(ent2->getCharsIguales() == 4, "Calculo mal el segundo termino (charsiguales)");
	res.assertTrue(ent1->getCharsIguales() == 0, "Calculo mal el primer termino (charsiguales)");
	BitStream bs("archivoFC");
	char c;
	string str;
	bs.get(c);
	str = string(1, c);
	res.assertTrue(str == "b", "Error al leer letras primer termino");
	bs.get(c);
	str = string(1, c);
	res.assertTrue(str == "a", "Error al leer letras primer termino");
	bs.get(c);
	str = string(1, c);
	res.assertTrue(str == "r", "Error al leer letras primer termino");
	bs.get(c);
	str = string(1, c);
	res.assertTrue(str == "c", "Error al leer letras primer termino");
	bs.get(c);
	str = string(1, c);
	res.assertTrue(str == "o", "Error al leer letras primer termino");
	Compresor com(&bs);

	res.assertTrue(com.leerDelta() == 2, "No guardo correctamente la cantidad de docs");
	EnteroLargo offset = leerNumeroVariableLargo(&bs, 7);
	res.assertTrue(offset == 0, "No guardo correctamente el offset del primero");
	//chequeo el 2do termino
	bs.omitByte();
	bs.get(c);
	str = string(1, c);
	res.assertTrue(str == "a", "Error al leer letras segundo termino");
	bs.get(c);
	str = string(1, c);
	res.assertTrue(str == "s", "Error al leer letras segundo termino");
	bs.get(c);
	str = string(1, c);
	res.assertTrue(str == "a", "Error al leer letras segundo termino");
	bs.get(c);
	bs.close();

	delete ent1;
	delete ent2;
	delete t1;
	delete t2;
	return res;
}

ResultadoTest PruebaArchivoFrontCoding::escribirConCoincidenciasBloque4() {
	ResultadoTest res("escribirConCoincidenciasBloque4");
	ArchivoFrontCoding arch("archivoFC6", "archivoPtrosFC6", 4, ios_base::out);

	Termino * t1 = (this->crearTermino("barco", 2, this->crearDocumento(3, 2, 3, 5),this->crearDocumento(4, 2, 3, 5)));
	arch.escribir(*t1);
	t1= this->crearTermino("barcasa", 1, this->crearDocumento(3, 2, 3, 5));
	arch.escribir(*t1);
	t1=this->crearTermino("besaban", 1, this->crearDocumento(3, 2, 3, 5));
	arch.escribir(*t1);
	t1=this->crearTermino("china", 1, this->crearDocumento(3, 2, 3, 5));
	arch.escribir(*t1);
	t1=this->crearTermino("chinitos", 1, this->crearDocumento(3, 2, 3, 5));
	arch.escribir(*t1);
	t1=this->crearTermino("en", 1, this->crearDocumento(3, 2, 3, 5));
	arch.escribir(*t1);
	t1=this->crearTermino("habia", 1, this->crearDocumento(3, 2, 3, 5));
	arch.escribir(*t1);
	t1=this->crearTermino("la", 1, this->crearDocumento(3, 2, 3, 5));
	arch.escribir(*t1);
	t1=this->crearTermino("patitos", 1, this->crearDocumento(3, 2, 3, 5));
	arch.escribir(*t1);
	t1=this->crearTermino("puto", 1, this->crearDocumento(3, 2, 3, 5));
	arch.escribir(*t1);
	t1=this->crearTermino("putitos", 1, this->crearDocumento(3, 2, 3, 5));
	arch.escribir(*t1);
	t1=this->crearTermino("que", 1, this->crearDocumento(3, 2, 3, 5));
	arch.escribir(*t1);
	arch.close();
	BitStream bs("archivoFC6");
	string str;
	verificarString("barco",bs, res);
	Compresor com(&bs);
	res.assertTrue(com.leerDelta() == 2, "No guardo correctamente la cantidad de docs");
	EnteroLargo offset = leerNumeroVariableLargo(&bs, 7);
	res.assertTrue(offset == 0, "No guardo correctamente el offset del primero");
	bs.omitByte();
	//chequeo el 2do termino

	verificarString("asa",bs, res);
	com.leerDelta();
	leerNumeroVariableLargo(&bs, 7);
	bs.omitByte();

	verificarString("esaban",bs, res);
	com.leerDelta();
	leerNumeroVariableLargo(&bs, 7);
	bs.omitByte();

	verificarString("china",bs, res);
	com.leerDelta();
	leerNumeroVariableLargo(&bs, 7);
	bs.omitByte();

	verificarString("chinitos",bs, res);
	com.leerDelta();
	leerNumeroVariableLargo(&bs, 7);
	bs.omitByte();

	verificarString("en",bs, res);
	com.leerDelta();
	leerNumeroVariableLargo(&bs, 7);
	bs.omitByte();

	verificarString("habia",bs, res);
	com.leerDelta();
	leerNumeroVariableLargo(&bs, 7);
	bs.omitByte();

	verificarString("la",bs, res);
	com.leerDelta();
	leerNumeroVariableLargo(&bs, 7);
	bs.omitByte();

	verificarString("patitos",bs, res);
	com.leerDelta();
	leerNumeroVariableLargo(&bs, 7);
	bs.omitByte();

	verificarString("uto",bs, res);
	com.leerDelta();
	leerNumeroVariableLargo(&bs, 7);
	bs.omitByte();

	verificarString("itos",bs, res);
	com.leerDelta();
	leerNumeroVariableLargo(&bs, 7);
	bs.omitByte();

	verificarString("que",bs, res);
	com.leerDelta();
	leerNumeroVariableLargo(&bs, 7);
	bs.omitByte();


	return res;
}
ResultadoTest PruebaArchivoFrontCoding::leerBloque() {
	ResultadoTest res("leerBloque");
	ArchivoFrontCoding arch("archivoFC5", "archivoPtrosFC5", 2, ios_base::out);
	Termino * t1 = this->crearTermino("bar", 1, this->crearDocumento(3, 2, 3, 5));
	Termino * t3 = this->crearTermino("barcasa", 2, this->crearDocumento(1, 2, 1, 2), this->crearDocumento(3, 2, 3, 5));
	Termino * t2 = this->crearTermino("barco", 2, this->crearDocumento(1, 2, 1, 2), this->crearDocumento(3, 2, 3, 5));
	Termino * t4 = this->crearTermino("bartola", 1, this->crearDocumento(3, 2, 3, 5));
	Termino * t5 = this->crearTermino("bartolita", 2, this->crearDocumento(1, 2, 1, 2), this->crearDocumento(3, 2, 3, 5));
	Termino * t6 = this->crearTermino("cama", 1, this->crearDocumento(3, 2, 3, 5));

	EntradaIndice * ent1 = arch.escribir(*t1);
	EntradaIndice * ent2 = arch.escribir(*t2);
	EntradaIndice * ent3 = arch.escribir(*t3);
	EntradaIndice * ent4 = arch.escribir(*t4);
	EntradaIndice * ent5 = arch.escribir(*t5);
	EntradaIndice * ent6 = arch.escribir(*t6);
	arch.close();
	delete t1;
	delete t2;
	delete t3;
	delete t4;
	delete t5;
	delete t6;

	ArchivoFrontCoding arch2("archivoFC5", "archivoPtrosFC5", 2, ios_base::in);

	//agrego las entradas del bloque2.
	list<EntradaIndice> entradas;
	entradas.push_back(*ent3);
	entradas.push_back(*ent4);

	map<string, Termino*> * palabrasBloque = arch2.leerBloque(entradas);
	map<string, Termino*>::iterator it = palabrasBloque->begin();

	//chequeo los terminos del bloque.
	res.assertEquals("barcasa",(*it).second->getCaracteres());
	it++;
	res.assertEquals("bartola",(*it).second->getCaracteres());

	delete ent1;
	delete ent2;
	delete ent3;
	delete ent4;
	delete ent5;
	delete ent6;
	return res;
}

ResultadoTest PruebaArchivoFrontCoding::leerBloqueTam4() {
	ResultadoTest res("leerBloqueTam4");
	ArchivoFrontCoding arch("archivoFC7", "archivoPtrosFC7", 4, ios_base::out);
	Termino * t1 = this->crearTermino("bar", 1, this->crearDocumento(3, 2, 3, 5));
	Termino * t2 = this->crearTermino("barco", 2, this->crearDocumento(1, 2, 1, 2), this->crearDocumento(3, 2, 3, 5));
	Termino * t3 = this->crearTermino("barcasa", 2, this->crearDocumento(1, 2, 1, 2), this->crearDocumento(3, 2, 3, 5));
	Termino * t4 = this->crearTermino("bartola", 1, this->crearDocumento(3, 2, 3, 5));
	Termino * t5 = this->crearTermino("bartolita", 2, this->crearDocumento(1, 2, 1, 2), this->crearDocumento(3, 2, 3, 5));
	Termino * t6 = this->crearTermino("cama", 1, this->crearDocumento(3, 2, 3, 5));

	EntradaIndice * ent1 = arch.escribir(*t1);
	EntradaIndice * ent2 = arch.escribir(*t2);
	EntradaIndice * ent3 = arch.escribir(*t3);
	EntradaIndice * ent4 = arch.escribir(*t4);
	EntradaIndice * ent5 = arch.escribir(*t5);
	EntradaIndice * ent6 = arch.escribir(*t6);
	arch.close();
	delete t1;
	delete t2;
	delete t3;
	delete t4;
	delete t5;
	delete t6;

	ArchivoFrontCoding arch2("archivoFC7", "archivoPtrosFC7", 2, ios_base::in);

	//agrego las entradas del bloque2.
	list<EntradaIndice> entradas;
	entradas.push_back(*ent1);
	entradas.push_back(*ent2);
	entradas.push_back(*ent3);
	entradas.push_back(*ent4);

	map<string, Termino*> * palabrasBloque = arch2.leerBloque(entradas);
	map<string, Termino*>::iterator it = palabrasBloque->begin();

	//chequeo los terminos del bloque.
	res.assertEquals("bar",(*it).second->getCaracteres());

	it++;
	res.assertEquals("barcasa",(*it).second->getCaracteres());

	it++;
	res.assertEquals("barco",(*it).second->getCaracteres());

	it++;
	res.assertEquals("bartola",(*it).second->getCaracteres());

	delete ent1;
	delete ent2;
	delete ent3;
	delete ent4;
	delete ent5;
	delete ent6;
	return res;
}

ResultadoTest PruebaArchivoFrontCoding::escribirSinCoincidencias() {
	ResultadoTest res("escribirSinCoincidencias");
	ArchivoFrontCoding arch("archivoFC2", "archivoPtrosFC2", 2, ios_base::out);

	Termino * t1 = this->crearTermino("ala", 2, this->crearDocumento(1, 2, 1, 2), this->crearDocumento(3, 2, 3, 5));
	Termino * t2 = this->crearTermino("casa", 1, this->crearDocumento(3, 2, 3, 5));
	EntradaIndice * ent1 = arch.escribir(*t1);
	EntradaIndice * ent2 = arch.escribir(*t2);

	arch.close();

	res.assertTrue(ent1->getCharsDistintos() == 3, "Calculo mal el primer termino (charsdistintos)");
	res.assertTrue(ent2->getCharsDistintos() == 4, "Calculo mal el segundo termino (charsdistintos)");
	res.assertTrue(!ent2->getPrincipal(), "El segundo fue marcado como ppal");
	res.assertTrue(ent1->getPrincipal(), "El primero no fue marcado como ppal");
	res.assertTrue(ent2->getCharsIguales() == 0, "Calculo mal el segundo termino (charsiguales)");
	res.assertTrue(ent1->getCharsIguales() == 0, "Calculo mal el primer termino (charsiguales)");
	BitStream bs("archivoFC2");
	char c;
	string str;
	bs.get(c);
	str = string(1, c);
	res.assertTrue(str == "a", "Error al leer letras primer termino");
	bs.get(c);
	str = string(1, c);
	res.assertTrue(str == "l", "Error al leer letras primer termino");
	bs.get(c);
	str = string(1, c);
	res.assertTrue(str == "a", "Error al leer letras primer termino");

	EnteroLargo offset = leerNumeroVariable(&bs, 7);
	res.assertTrue(offset == 0, "No guardo correctamente el offset del primero");
	//chequeo el 2do termino
	bs.get(c);
	str = string(1, c);
	res.assertTrue(str == "c", "Error al leer letras segundo termino");
	bs.get(c);
	str = string(1, c);
	res.assertTrue(str == "a", "Error al leer letras segundo termino");
	bs.get(c);
	str = string(1, c);
	res.assertTrue(str == "s", "Error al leer letras segundo termino");
	bs.get(c);
	str = string(1, c);
	res.assertTrue(str == "a", "Error al leer letras segundo termino");
	bs.close();
	delete ent1;
	delete ent2;
	delete t1;
	delete t2;
	return res;
}

ResultadoTest PruebaArchivoFrontCoding::escribirMasDeUnBloqueConCoincidencia() {
	ResultadoTest res("escribirMasDeUnBloqueConCoincidencia");
	ArchivoFrontCoding arch("archivoFC3", "archivoPtrosFC", 2, ios_base::out);
	Termino * t1 = this->crearTermino("ala", 2, this->crearDocumento(1, 2, 1, 2), this->crearDocumento(3, 2, 3, 5));
	Termino * t2 = this->crearTermino("casa", 1, this->crearDocumento(3, 2, 3, 5));
	Termino * t3 = this->crearTermino("casona", 1, this->crearDocumento(1, 2, 3, 5));

	EntradaIndice * ent1 = arch.escribir(*t1);
	EntradaIndice * ent2 = arch.escribir(*t2);
	EntradaIndice * ent3 = arch.escribir(*t3);
	arch.close();
	res.assertTrue(ent1->getCharsDistintos() == 3, "Calculo mal el primer termino (charsdistintos)");
	res.assertTrue(ent1->getCharsIguales() == 0, "Calculo mal el primer termino (charsiguales)");
	res.assertTrue(ent1->getPrincipal(), "El primero no fue marcado como ppal");

	res.assertTrue(ent2->getCharsDistintos() == 4, "Calculo mal el segundo termino (charsdistintos)");
	res.assertTrue(ent2->getCharsIguales() == 0, "Calculo mal el segundo termino (charsiguales)");
	res.assertTrue(!ent2->getPrincipal(), "El segundo fue marcado como ppal");

	res.assertTrue(ent3->getCharsDistintos() == 6, "Calculo mal el tercer termino (charsdistintos)");
	res.assertTrue(ent3->getCharsIguales() == 0, "Calculo mal el tercer termino (charsiguales)");
	res.assertTrue(ent3->getPrincipal(), "El tercer no fue marcado como ppal");

	delete ent1;
	delete ent2;
	delete ent3;
	delete t1;
	delete t2;
	delete t3;
	return res;
}

//Escribo una serie de entradas y finalmente chequeo que se recuperen todos los documentos mediante el proxy.
ResultadoTest PruebaArchivoFrontCoding::leerCabeceraYDocumentos() {
	InfoRepositorioActual::Instance()->setCantidadArchivos(3);
	ResultadoTest res("leerCabeceraYDocumentos");
	ArchivoFrontCoding arch("archivoFC4", "archivoPtrosFC4", 2, ios_base::out);

	//creo los terminos;

	Termino * t1 = this->crearTermino("ala", 2, this->crearDocumento(1, 2, 1, 2), this->crearDocumento(5, 6, 1, 2, 3, 4, 5, 6));
	Termino * t2 = this->crearTermino("casa", 2, this->crearDocumento(2, 2, 7, 10), this->crearDocumento(3, 1, 1));
	Termino * t3 = this->crearTermino("casona", 3, this->crearDocumento(0, 2, 3, 5), this->crearDocumento(1, 2, 7, 8), this->crearDocumento(2, 1, 2));
	//Escribo
	EntradaIndice * ent1 = arch.escribir(*t1);
	EntradaIndice * ent2 = arch.escribir(*t2);
	EntradaIndice * ent3 = arch.escribir(*t3);
	arch.close();
	delete t1;
	delete t2;
	delete t3;

	// verifico que me traiga los documentos

	ArchivoFrontCoding arch2("archivoFC4", "archivoPtrosFC4", 2, ios_base::in);
	t1 = arch2.leerCabecera(*ent1);
	t3 = arch2.leerCabecera(*ent3);
	res.assertEquals(t1->getDocumentos()->size(), 2);
	res.assertEquals(t3->getDocumentos()->size(), 3);
	//esto chequea que no se vaya de nuevo al proxy
	arch2.close();
	res.assertEquals(t3->getDocumentos()->size(), 3);

	//Ahora que se quedo sin conexion a los documentos chequeo que los documentos recuperados sean los que deben ser.
	list<Documento*>::iterator it = t1->getDocumentos()->begin();
	res.assertEquals(1, (*it)->getNumero());
	it++;
	res.assertEquals(5, (*it)->getNumero());
	//los del termino 2
	EnteroLargo i = 0;
	list<Documento*>::iterator it2;
	for (it2 = t3->getDocumentos()->begin(); it2 != t3->getDocumentos()->end(); ++it2) {
		res.assertEquals(i, (*it2)->getNumero());
		i++;
	}
	delete t1;
	delete t3;
	delete ent1;
	delete ent2;
	delete ent3;
	return res;
}

void PruebaArchivoFrontCoding::before() {
	InfoRepositorioActual::Instance()->setCantidadArchivos(5);
	this->borrarArchivo("archivoPtrosFC");
	this->borrarArchivo("archivoFC2");
	this->borrarArchivo("archivoPtrosFC2");
	this->borrarArchivo("archivoFC3");
	this->borrarArchivo("archivoPtrosFC3");
	this->borrarArchivo("archivoFC4");
	this->borrarArchivo("archivoPtrosFC4");
	this->borrarArchivo("archivoFC5");
	this->borrarArchivo("archivoPtrosFC");

}

void PruebaArchivoFrontCoding::run() {
	ResultadoTest resTotal("----------------TEST_ARCHIVO_FRONT_CODING------------------");
//	resTotal.assertTrue(this->escribirConCoincidencias().getResultado(), "Test1");
//	resTotal.assertTrue(this->escribirSinCoincidencias().getResultado(), "Test2");
//	resTotal.assertTrue(this->escribirMasDeUnBloqueConCoincidencia().getResultado(), "Test3");
	resTotal.assertTrue(this->leerCabeceraYDocumentos().getResultado(), "Test4");
	resTotal.assertTrue(this->leerBloque().getResultado(), "Test5");
	resTotal.assertTrue(this->escribirConCoincidenciasBloque4().getResultado(), "Test6");
	resTotal.assertTrue(this->leerBloqueTam4().getResultado(), "Test7");
	resTotal.getResultado();
}


